package main

import (
	"encoding/hex"
	"fmt"
	"log"
	"sync"
	"time"
)

// ModbusParser Modbus报文解析器
type ModbusParser struct {
	serialManager *SerialManager
	isRunning     bool
	stopChan      chan struct{}
	mutex         sync.Mutex
	interval      time.Duration // 轮询间隔
	lastError     error
	lastResponse  string
}

// NewModbusParser 创建新的Modbus报文解析器
func NewModbusParser(serialManager *SerialManager) *ModbusParser {
	return &ModbusParser{
		serialManager: serialManager,
		isRunning:     false,
		stopChan:      make(chan struct{}),
		interval:      time.Second, // 默认1秒轮询一次
	}
}

// Start 启动Modbus报文解析器
func (mp *ModbusParser) Start() error {
	mp.mutex.Lock()
	defer mp.mutex.Unlock()

	if mp.isRunning {
		return fmt.Errorf("Modbus解析器已经在运行")
	}

	// 检查串口是否打开
	if !mp.serialManager.IsPortOpen() {
		return fmt.Errorf("串口未打开，无法启动Modbus解析器")
	}

	mp.isRunning = true
	mp.stopChan = make(chan struct{})

	// 启动解析协程
	go mp.parseLoop()

	return nil
}

// Stop 停止Modbus报文解析器
func (mp *ModbusParser) Stop() {
	mp.mutex.Lock()
	defer mp.mutex.Unlock()

	if !mp.isRunning {
		return
	}

	close(mp.stopChan)
	mp.isRunning = false
}

// SetInterval 设置轮询间隔
func (mp *ModbusParser) SetInterval(interval time.Duration) {
	mp.mutex.Lock()
	defer mp.mutex.Unlock()
	mp.interval = interval
}

// GetLastError 获取最后一次错误
func (mp *ModbusParser) GetLastError() error {
	mp.mutex.Lock()
	defer mp.mutex.Unlock()
	return mp.lastError
}

// GetLastResponse 获取最后一次响应
func (mp *ModbusParser) GetLastResponse() string {
	mp.mutex.Lock()
	defer mp.mutex.Unlock()
	return mp.lastResponse
}

// IsRunning 检查解析器是否正在运行
func (mp *ModbusParser) IsRunning() bool {
	mp.mutex.Lock()
	defer mp.mutex.Unlock()
	return mp.isRunning
}

// parseLoop Modbus报文解析循环
func (mp *ModbusParser) parseLoop() {
	log.Println("Modbus解析器已启动")

	for {
		select {
		case <-mp.stopChan:
			log.Println("Modbus解析器已停止")
			return
		default:
			// 发送Modbus请求并解析响应
			err := mp.sendAndParseModbusRequest()

			mp.mutex.Lock()
			mp.lastError = err
			mp.mutex.Unlock()

			if err != nil {
				log.Printf("Modbus解析错误: %v, 将在5秒后重试", err)
				// 出错时等待5秒后重试
				select {
				case <-mp.stopChan:
					log.Println("Modbus解析器已停止")
					return
				case <-time.After(5 * time.Second):
					// 继续重试
				}
			} else {
				// 正常轮询间隔
				select {
				case <-mp.stopChan:
					log.Println("Modbus解析器已停止")
					return
				case <-time.After(mp.interval):
					// 继续下一次轮询
				}
			}
		}
	}
}

// sendAndParseModbusRequest 发送Modbus请求并解析响应
func (mp *ModbusParser) sendAndParseModbusRequest() error {
	// 准备Modbus请求: 01 03 00 00 00 05
	request := []byte{0x01, 0x03, 0x00, 0x00, 0x00, 0x05}

	// 添加Modbus CRC校验
	requestWithCRC := AppendModbusCRC(request)

	// 将请求转换为十六进制字符串
	requestHex := hex.EncodeToString(requestWithCRC)

	// 发送请求并等待响应，期望接收20个字节，超时时间为1秒
	responseHex, err := mp.sendModbusRequest(requestHex, 20, 1000)
	if err != nil {
		return fmt.Errorf("发送Modbus请求失败: %v", err)
	}

	// 解析并打印响应
	err = mp.parseModbusResponse(responseHex)
	if err != nil {
		return fmt.Errorf("解析Modbus响应失败: %v", err)
	}

	return nil
}

// sendModbusRequest 发送Modbus请求并等待响应
func (mp *ModbusParser) sendModbusRequest(requestHex string, rxLen int, timeoutMs int) (string, error) {
	// 使用ComTxRx函数发送请求并接收响应
	txBuf, err := hex.DecodeString(requestHex)
	if err != nil {
		return "", fmt.Errorf("无效的十六进制请求数据: %v", err)
	}

	txLen := len(txBuf)
	rxBuf := make([]byte, rxLen)
	timeout := time.Duration(timeoutMs) * time.Millisecond

	// 调用SerialManager的ComTxRx方法
	n, err := mp.serialManager.ComTxRx(txBuf, txLen, rxBuf, rxLen, timeout)

	// 即使有错误，也返回已接收的数据
	if n > 0 {
		responseHex := hex.EncodeToString(rxBuf[:n])

		mp.mutex.Lock()
		mp.lastResponse = responseHex
		mp.mutex.Unlock()

		return responseHex, err
	}

	return "", err
}

// parseModbusResponse 解析Modbus响应
func (mp *ModbusParser) parseModbusResponse(responseHex string) error {
	// 将十六进制字符串转换为字节数组
	responseBytes, err := hex.DecodeString(responseHex)
	if err != nil {
		return fmt.Errorf("无效的十六进制响应数据: %v", err)
	}

	// 检查响应长度
	if len(responseBytes) < 3 {
		return fmt.Errorf("响应数据太短: %d 字节", len(responseBytes))
	}

	// 验证Modbus CRC校验
	if !VerifyModbusCRC(responseBytes) {
		return fmt.Errorf("CRC校验失败")
	}

	// 检查功能码
	if responseBytes[1] != 0x03 {
		return fmt.Errorf("无效的功能码: %02X", responseBytes[1])
	}

	// 获取数据长度
	dataLength := int(responseBytes[2])
	if len(responseBytes) < 3+dataLength+2 { // 3字节头部 + 数据 + 2字节CRC
		return fmt.Errorf("数据长度不匹配: 期望 %d 字节, 实际 %d 字节", 3+dataLength+2, len(responseBytes))
	}

	// 提取数据部分
	data := responseBytes[3 : 3+dataLength]

	// 两个字节一组打印
	fmt.Println("Modbus响应数据:")
	for i := 0; i < len(data); i += 2 {
		if i+1 < len(data) {
			// 两个字节一组
			value := uint16(data[i])<<8 | uint16(data[i+1])
			fmt.Printf("数据[%d:%d]: %04X (%d)\n", i, i+1, value, value)
		} else {
			// 最后一个单独的字节
			fmt.Printf("数据[%d]: %02X (%d)\n", i, data[i], data[i])
		}
	}

	return nil
}
